#pragma once
#include<iostream>
#include<pthread.h>
#include<vector>
#include<unistd.h>
#include "sem.hpp"

template<class T>
class RingQueue
{
public:
    RingQueue(int num):ring_queue_(num),
    num_(num),
    p_index_(0),
    c_index_(0),
    space_sem_(num),
    data_sem_(0)
    {
        pthread_mutex_init(&p_mtx,nullptr);
        pthread_mutex_init(&c_mtx,nullptr);
    }
    void push(const T& in)//生产者
    {
        space_sem_.p();//p申请操作   向空间信号量申请一个资源,信号量内计数器--
        pthread_mutex_lock(&p_mtx);//在多线程情况下，增加了两种关系 生产者和生产者，消费者和消费者
        //在信号量之后加锁，因为多个线程先申请信号量预订资源，保证每个有信号量的线程都一定能拿到自己想要的资源
        ring_queue_[p_index_++] = in;
        p_index_ %= num_;
        
        pthread_mutex_unlock(&p_mtx);

        data_sem_.v();//v释放操作   数据新增，数据信号量内计数器++，

    }

    void pop(T* out)//消费者
    {
        data_sem_.p();//p向数据信号量申请一个数据，数据信号量内计数器--，表示资源少了一个
        pthread_mutex_lock(&c_mtx);
        *out = ring_queue_[c_index_++];
        c_index_ %= num_;
        pthread_mutex_unlock(&c_mtx);

        space_sem_.v();//v向信号量释放一个数据，计数器++，表示可以生产的数据多了一个
    }
    ~RingQueue()
    {
        pthread_mutex_destroy(&p_mtx);
        pthread_mutex_destroy(&c_mtx);
    }
private:
    std::vector<T> ring_queue_;//环形队列数组
    int num_;//环形队列容量
    int p_index_;//生产者下表
    int c_index_;//消费者下表
    Sem space_sem_;//空间信号量
    Sem data_sem_;//数据信号量
    pthread_mutex_t p_mtx;//生产者加锁
    pthread_mutex_t c_mtx;//消费者加锁
};